<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> 
  <title>WebCrypto国密算法演示</title>
  <link rel="stylesheet" href="./static/style.css?v=8">
</head>

<body>
  <header>
    <h1>WebCrypto国密算法演示</h1>
    <ul style="line-height: 24px;">
      <li><span id="no-support-tips">请使用360安全浏览器等支持国密算法的浏览器测试</span> <a href="https://www.w3.org/TR/WebCryptoAPI/">Web Cryptography API</a> 国密算法接口。</li>
      <li>360安全浏览器遵循<a href="http://www.gmbz.org.cn/main/viewfile/20210627114933258301.html">《GM/T 0087-2020 浏览器密码应用接口规范》</a>实现了 Web Cryptography API 对国密算法的支持。</li>
    </ul>
  </header>
  <main>
    <section class="examples">
      <div>
        <span class="operate-btn performance-button all-performance-button">性能测试</span>
      </div>
      <section class="encrypt-decrypt sm3">
        <h2 class="encrypt-decrypt-heading">SM3</h2>
        <section class="encrypt-decrypt-controls">
          <div class="message-control">
            <textarea type="text" id="sm3-message" name="message" size="25" placeholder="请输入要计算摘要的内容"></textarea>
          </div>
          <div class="operation">
            <span class="operate-btn encrypt-button">计算摘要</span>
          </div>
          <div class="ciphertext">摘要:<span class="ciphertext-value"></span></div>
        </section>
      </section>

      <section class="encrypt-decrypt">
        <h2 class="encrypt-decrypt-heading">SM4<span id="encrypt-type" class="encrypt-type"><i id="cbc">CBC</i><i id='gcm'>GCM</i><i id="ctr">CTR</i></span></h2>
        <section class="encrypt-decrypt-controls sm4 sm4-html">
          <div class="message-control">
            <div class="examples-tips">解密文本可以是：Hex、Base64、8bit数（逗号或空格分隔、十进制或二进制），一次只能输入一种格式。</div>
            <textarea type="text" class="crypt-message" name="message" rows="6" placeholder="待加密、解密文本"></textarea>
            <div class="examples-tips">KEY 和 IV 可以是：字符串(length=16)、(length=32)Hex、(length=24)Base64；优先匹配为Hex和Base64。</div>
            KEY: <input type="text" class="key" placeholder="解密必填">
            IV: <input type="text" class="iv" placeholder="解密必填">
            
            </div>
          <div class="operation">
            <span class="operate-btn encrypt-button">加密</span>
            <span class="operate-btn decrypt-button">解密</span>
            <span class="error-tip"></span>
          </div>
          <div class="decrypted">原文：<textarea rows="5" class="decrypted-value"></textarea ></div>
          <div class="ciphertext">
            Base64密文：<textarea rows="4" class="ciphertext-base64"></textarea>
            Hex密文：<textarea rows="4" class="ciphertext-hex"></textarea>
            Binary：<textarea rows="4" class="ciphertext-binary"></textarea>
          </div>
        </section>

      </section>

    </section>
  </main>
  
  <div class="layui-layer-shade"></div>
  <div class="all-performance">
    <div class="performance-title">
      一键性能测试<span style="font-size: 14px;font-weight: normal;">（单位：Mbps）</span>
      <span class="close-all-performance">×</span>
    </div>
    <table>
      <thead>
        <tr><th>算法\数据大小</th><th>4K</th><th>64K</th><th>128K</th><th>512K</th><th>1M</th></tr>
      </thead>
      <tbody>
        <tr id="tr-sm3"><th>SM3</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-cbc-encrypt"><th>SM4-CBC加密</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-cbc-decrypt"><th>SM4-CBC解密</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-gcm-encrypt"><th>SM4-GCM加密</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-gcm-decrypt"><th>SM4-GCM解密</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-ctr-encrypt"><th>SM4-CTR加密</th><td></td><td></td><td></td><td></td><td></td></tr>
        <tr id="tr-sm4-ctr-decrypt"><th>SM4-CTR解密</th><td></td><td></td><td></td><td></td><td></td></tr>
      </tbody>
    </table>
    <div style="text-align: center;font-size: 16px;padding: 0 0 6px;">
      算法运行：
      <span id="testCount">
        <input id="testTimes" step=100 type="number" min=100 max=3000 value=100>
        <input id="testTime" step=100 type="number" min=100 max=10000 value=200>
        <input id="testDataSize" step=100 type="number" min=50 max=2000 value=100>
      </span>
      <select id="testType" style="width: initial;" onchange="chgTestType(this);"><option value="0">次</option><option value="1" selected>毫秒</option><option value="2">MB</option></select>
      <span id="performancing"></span>
    </div>
    <div style="text-align: center;padding: 20px 0 29px;">
      <span class="operate-btn performance-button start-all-performance-button">开始测试</span>
      <span class="operate-btn stop-all-performance-button">停止</span>
    </div>
  </div>
  <script src="./static/common.js?v=9"></script>
  <script src="./static/utils.js?v=8"></script>
  <script src="./static/sm3.js?v=8"></script>
  <script src="./static/sm4.js?v=8"></script>
  
  <script>
    async function init() {
      let rst;
      setTimeout(()=>{
        if(!rst){ // 不支持国密 API 的浏览器禁用按钮
          appendToHead('style', 'text/css', `span[class*="-button"] {background: #ccc!important;}`);
          $('#no-support-tips').classList = 'no-support-tips';
        }else{ // 支持国密 API 的浏览器加载加密对应JS文件
          SM3Init();
          SM4Init((path)  => $(".sm4-cbc").querySelector(path), 'SM4-CBC', '烟村四五家');
          SM4Init((path)  => $(".sm4-gcm").querySelector(path), 'SM4-GCM', '亭台六七座');
          SM4Init((path)  => $(".sm4-ctr").querySelector(path), 'SM4-CTR', '八九十支花');

          
          $('#cbc').classList.add('active');
          $('.sm4-cbc').classList.add('active');

          $("#encrypt-type").addEventListener('click', (e) => {
            let node = e.target.previousSibling;
            while(node){
              node.classList.remove('active');
              node = node.previousSibling
            }
            node = e.target.nextSibling;
            while(node){
              node.classList.remove('active');
              node = node.nextSibling
            }
            e.target.classList.add('active');

            document.querySelectorAll('.sm4').forEach(n=>n.classList.remove('active'));
            $('.sm4-' + e.target.id).classList.add('active');
          });

          // 一键性能测试
          const shadeDom = $('.layui-layer-shade');
          const allPerformanceDom = $('.all-performance');
          const allPerformanceDisplay = (display) => {
            shadeDom.style.display = allPerformanceDom.style.display = display;
          };
          shadeDom.addEventListener('click', () => allPerformanceDisplay('none'));
          $('.close-all-performance').addEventListener('click', () => allPerformanceDisplay('none'));
          $(".all-performance-button").addEventListener('click', () => {
            allPerformanceDisplay('block');

            window.chgTestType = (e)=>{
              $('#testTimes').style.display = $('#testTime').style.display = $('#testDataSize').style.display = 'none';
              document.querySelectorAll('#testCount > input')[e.value].style.display = 'inline';
            }

            const startPerformanceBtn = $(".start-all-performance-button");
            window.stopPerformanceBtn = $(".stop-all-performance-button");
            if(!window.performanceData) {
              startPerformanceBtn.textContent = '正在生成检测数据...';
              
              initPerformanceData(()=>{
                if(startPerformanceBtn.textContent != '重新测试'){
                  startPerformanceBtn.textContent = '开始测试';
                }
                startPerformanceBtn.addEventListener('click', () => { // 检测数据初始化完成，绑定检测事件
                  window.interruptPerformance = false;
                  startAllPerformace();
                });
                stopPerformanceBtn.addEventListener('click', () => {
                  if(window.durationPerformance){
                    stopPerformanceBtn.textContent = '停止中...'
                    window.interruptPerformance = true;
                  }
                });
              });
            }
          });
          
        }
      }, 20);
      rst = await window.crypto.subtle.digest({name: "SM3"}, encode(''));
    };
    init();
  </script>

</body>

</html>